public class AssetEntitlementListController{

    private final Asset asst;
    // -- Local variables
    //List collection to store support program associated with this Asset. 
    //The support programs will contain inside Asset row as object...so, the list object should be of Asset type.
    List<Asset> spList = new List<Asset>();
    
    //List collection to store support program which is the lookup SP for an Account (Default SP)
    List<Support_Program__c> acSpList = new List<Support_Program__c>();

    //Asset.Id
    Id asstId;

    //Asset's name
    String asstName;

    //Account.Id, the parent of this Asset.
    Id acId;

    //SPId of the parent account of this Asset
    Id spIdOnAc;
        
    //Stores supportprogram ids that are retrieved from spList (directly related to this asset).
    //The items in this list will not be added in the allSupportProgramIds. This way we don't have duplicate SPs under dropdown.
    Set<Id> assetSupportProgramIds = new Set<Id>();

    //Local variable to store all SPs that are selectible in Support Program dropdown.
    //This is useful to draw entitlement lists when user selects 'All' from the dropdown.
    List<Id> allSupportProgramIds = new List<Id>();
    
    //Local variable to store all SPs with Name and Id (Name with 80 chars space+'|'+Id)
    List<String> allSPNameAndIDs = new List<String>();
    
    //Local variable that holds currently selected program option in dropdown.
    //At first, it will be null and will hve value only when user selects an option from dropdown
    String programs;
    
    //Local variable to store the selected SP. The entitlement list is displayed on the basis of this selected SP.
    String selectedSP = 'All';  

    //Constructor
    public AssetEntitlementListController(ApexPages.StandardController stdController){
        this.asst = (Asset)stdController.getRecord();     
        //Store asset's id
        asstId = System.CurrentPageReference().getParameters().get('id');
        //Find and store this asset's parent account's id 
        List<Asset> lstAsst = new List<Asset>([SELECT Asset.Name, Asset.Account.Id FROM Asset where id=:asstId]);
        this.asstName = lstasst[0].Name;
        //Store parent account's id
        acId = lstAsst[0].Account.Id;    
        //Get lookup SPId of the parent account of this Asset
        Account[] allAcs = [Select Support_Program__c from Account where Id=:acId];
        if(allAcs.size()>0){
            spIdOnAc = allAcs[0].Support_Program__c;
        }
        //Load all support programs
        loadSupportPrograms();
        getItems();
    }  
    
    //Dummy constructor for testMethod
    public AssetEntitlementListController(Asset dc){
        this.asst = dc;
        asstId = dc.Id;
        this.asstName = dc.Name;
        acId = dc.Account.Id;
        System.debug('dummy constructor');      
        loadSupportPrograms();
        getItems();
    }         
    
    //Loads support programs associated to both Asset and Account
    private void loadSupportPrograms(){
        //Support Programs list associated to this Asset
        spList = [Select Id, (Select Support_Program__c, Support_Program__r.Name From a.Program_Assets__r where Support_Program__r.Apply_To_All_Contacts_In_Account__c=True Order By Support_Program__r.Name) From Asset a Where a.Id =:asstId];
        //Support Programs that is the lookup SP of the parent account of this asset IF 'Apply_To_All_Contacts_In_Account__c' is true.
        acSpList= [Select Id, Name From Support_Program__c where Id=:spIdOnAc and Apply_To_All_Contacts_In_Account__c=True Order By Name];      
        
        //spList returns only one row containing an object of Support_Program__c.
        //So we need to iterate through this object to get all support programs.
        for(Asset program : spList){
            for(Program_Asset__c pc : program.Program_Assets__r){            
                //Add this id into assetSupportProgramIds collection so that SPs in this collection do not repeat while storing in allSPNameAndIDs
                assetSupportProgramIds.add(pc.Support_Program__c);
                //Add this id into allSPNameAndIDs
                if(EntitlementList.HasEntForSP(pc.Support_Program__c)){
                    allSPNameAndIDs.add(EntitlementList.CombineSPNameAndID(pc.Support_Program__r.Name,pc.Support_Program__c));
                }
            }
        }

        //The acSpList contains just one record. So check if this sp is already included in assetSupportProgramIds. If so, remove the single row from acSpList.
        //This way, it can be declared that if the acSpList contains any row, then that has come from Account lookup, and not from other way, and must follow the rule while getting entitlement for this sp.
        if(acSpList.size()>0){
            Boolean moreLoop = True;
            for(Id spId : assetSupportProgramIds){
                if(moreLoop){
                    if(spId == acSpList[0].Id){
                        acSpList.remove(0);
                        moreLoop = False;
                    }
                }
            }
        }
        
        //If acSpList still has row, it means it was not repeated in assetSupportProgramIds and it is lookup SP for the account
        //--Add from acSpList into allSPNameAndIDs.
        if(acSpList.size()>0){
            if(EntitlementList.HasEntForSP(acSpList[0].Id)){
                allSPNameAndIDs.add(EntitlementList.CombineSPNameAndID(acSpList[0].Name,acSpList[0].Id));
            }
        }        
        
        //Sort this list
        allSPNameAndIDs.sort();
        for(String s : allSPNameAndIDs){
            //Get id from this list and add into allSupportProgramIds
            allSupportProgramIds.add(EntitlementList.GetIDFromCombineSP(s));                
        }
    }

    public String getAssetName(){     
        return this.asstName;
    }

    //Required by SelectOption
    //Returns list of support programs to be populated in 'Support Program' dropdown
    public List<SelectOption> getItems(){
        List<SelectOption> options = new List<SelectOption>();
        options.add(new SelectOption('All','All'));

        //Sort again just in case (though it is already sorted)
        allSPNameAndIDs.sort();
        for(String s : allSPNameAndIDs){
            //Add items into options for the dropdown
            options.add(new SelectOption(EntitlementList.GetIDFromCombineSP(s), EntitlementList.GetNameFromCombineSP(s)));
        }
        return options;
    }
    
    //Getter/Setter for programs variable. Holds currently selected option in dropdown
    public String getPrograms(){
        return programs;
    }
    public void setPrograms(String programs){
        this.programs = programs;
    }   
    
    //Returns if there is any entitlement to display for the selected SP from the dropdown.
    //This is the basis of displaying 'No Entitlements found for this...' label as well as displaying apex:pageBlockTable
    public Boolean getNoEntitlement(){
        List<EntitlementList.EntitlementWrapper> el = getEntitlement();
        return el.size()==0;        
    }
    
    //Main method that displays Entitlement List for selected support program.
    //This method calls another apex method 'getEntitlementList' in EntitlementList class with list of support programs' id as a parameter
    public List<EntitlementList.EntitlementWrapper> getEntitlement(){
        
        EntitlementList el = new EntitlementList();
        List<EntitlementList.EntitlementWrapper> entData;
        Boolean bDoCartesianProduct =False;
        //If programs is null or all, send all SPIDs as parameter so that all entitlements can be displayed
        if(programs==null || programs=='All'){
            entData = el.getEntitlementList(allSupportProgramIds, acSpList, bDoCartesianProduct);
        }
        //otherwise, send single SPID as parameter which is currently selected from the dropdown
        else{
            entData = el.getEntitlementList(new List<Id>{programs}, acSpList, bDoCartesianProduct);
        }
        return entData;
    }   
    
    //Returns new pagereference of new case window
    public PageReference CreateNewCase(){   
        try{
            String prmFunc = System.currentPageReference().getParameters().get('prmFunc');
            ID prmEntId = System.currentPageReference().getParameters().get('prmEntId');
            ID prmSpId = System.currentPageReference().getParameters().get('prmSPId');
            String prmEntName = System.currentPageReference().getParameters().get('prmEntName');
            String prmAstId ='';//(String)this.asst.Id;
            String prmAstName ='';//(String)this.asst.Name;
            EntitlementList el = new EntitlementList();
            Id contId = null;   // Account page will not have this info, pass null value. 
                                //EntitlementList class will take care of this null
            Id retUrlId = asstId;
            return el.CreateNewCase(retUrlId, contId, acId, prmFunc, prmEntId, prmspId, prmEntName, prmAstId, prmAstName);   
        }
        catch (Exception ex){
            return null;
        }
    }   
 
    
}